
#include <string.h>
#include "alloc.h"
#include "str.h"
#define LOG_TAG "XmlString"
#include "log.h"

#define STRING_MAP_SIZE 4

/********************** String ****************************/

String StringFrom(const char *ptr)
{
    static StringEty str;
    str.ptr = ptr;
    str.len = (int) strlen(ptr);
    return &str;
}

void StringSet(String str, const char *ptr)
{
    str->ptr = ptr;
    str->len = (int) strlen(ptr);
}

void StringClone(String str, String oldStr)
{
    if (oldStr == NULL) {
        str->ptr = NULL;
        str->len = 0;
    } else {
        str->ptr = oldStr->ptr;
        str->len = oldStr->len;
    }
}

bool StringIsEmpty(String str)
{
    return str->ptr == NULL || str->len <= 0;
}

void StringMove(String str, int dx)
{
    str->ptr += dx;
    str->len -= dx;
}

int StringIndex(String str, char c)
{
    if (StringIsEmpty(str)) return -1;
    int i;
    for (i = 0; i < str->len; i++) {
        if (str->ptr[i] == c) {
            return i;
        }
    }
    return -1;
}

int StringSubIndex(String str, String sub)
{
    if (StringIsEmpty(str) || StringIsEmpty(sub) || str->len < sub->len) {
        return -1;
    }

    char c = sub->ptr[0];
    int len = str->len - sub->len + 1;
    int i;
    for (i = 0; i < len; i++) {
        if (str->ptr[i] == c && memcmp(str->ptr + i, sub->ptr, (size_t) sub->len) == 0) {
            return i;
        }
    }
    return -1;
}

int StringLastIndex(String str, char c)
{
    if (StringIsEmpty(str)) return -1;
    int i;
    for (i = str->len - 1; i >= 0; i--) {
        if (str->ptr[i] == c) {
            return i;
        }
    }
    return -1;
}

int StringLastSubIndex(String str, String sub)
{
    if (StringIsEmpty(str) || StringIsEmpty(sub) || str->len < sub->len) {
        return -1;
    }

    char c = sub->ptr[0];
    int len = str->len - sub->len + 1;
    int i;
    for (i = len - 1; i >= 0; i--) {
        if (str->ptr[i] == c && memcmp(str->ptr + i, sub->ptr, (size_t) sub->len) == 0) {
            return i;
        }
    }
    return -1;
}

bool StringBeginWith(String str, String begin)
{
    if (StringIsEmpty(begin)) return true;

    if (StringIsEmpty(str) || str->len < begin->len) {
        return false;
    }
    if (str->ptr == begin->ptr) {
        return true;
    }
    return !memcmp(str->ptr, begin->ptr, (size_t) begin->len);
}

bool StringEqualStr(String str, const char *str2)
{
    if (str->len != (int) strlen(str2)) {
        return false;
    }
    if (str->ptr == str2) {
        return true;
    }
    return !memcmp(str->ptr, str2, (size_t) str->len);
}

bool StringEqual(String str, String str2)
{
    if (str->len != str2->len) {
        return false;
    }
    if (str->ptr == str2->ptr) {
        return true;
    }
    return !memcmp(str->ptr, str2->ptr, (size_t) str->len);
}

bool StringCaseEqual(String str, String str2)
{
    if (str->len != str2->len) {
        return false;
    }
    if (str->ptr == str2->ptr) {
        return true;
    }
    return !strncasecmp(str->ptr, str2->ptr, (size_t) str->len);
}

bool StringIgnoreCaseEqual(String str, const char *str2)
{
    if (str->len != (int) strlen(str2)) {
        return false;
    }
    if (str->ptr == str2) {
        return true;
    }
    return !strncasecmp(str->ptr, str2, (size_t) str->len);
}

/********************** StringMap ****************************/

void StringMapPut(StringMap map, String key, String val)
{
    if (map->items == NULL) {
        map->items = malloc_ct(StringMapItem, STRING_MAP_SIZE);
        if (map->items == NULL) {
            LOGE("Memory exhausted");
            return;
        }
        map->count = 0;
    } else if ((map->count + 1) % STRING_MAP_SIZE == 0) {
        void *tmp = malloc_ct(StringMapItem, map->count + 1 + STRING_MAP_SIZE);
        if (tmp == NULL) {
            LOGE("Memory exhausted");
            return;
        }
        memcpy(tmp, map->items, sizeof(StringMapItem) * map->count);
        free_ct(map->items);
        map->items = (StringMapItem*) tmp;
    }

    StringClone(&map->items[map->count].key, key);
    StringClone(&map->items[map->count].val, val);
    map->count++;
}

String StringMapGet(StringMap map, String key)
{
    int i;
    for (i = 0; i < map->count; i++) {
        if (StringEqual(&map->items[i].key, key)) {
            return &map->items[i].val;
        }
    }
    return NULL;
}

bool StringMapEqual(StringMap map, StringMap map2)
{
    if (map->count != map2->count) return false;
    int i;
    for (i = 0; i < map->count; i++) {
        if (!StringEqual(&map->items[i].key, &map2->items[i].key)) {
            return false;
        }
        if (!StringEqual(&map->items[i].val, &map2->items[i].val)) {
            return false;
        }
    }
    return true;
}

void StringMapFree(StringMap map)
{
    free_ct(map->items);
    map->items = NULL;
    map->count = 0;
}
